/*
* Purpose: Driver layer2 for controlling SD/MMC cards
*
* Author: Tristan
*
* Date: 2008/12/11
*
* Copyright Generalplus Corp. ALL RIGHTS RESERVED.
*
* Version : 1.06
*/
#include "drv_l1_timer.h"
#include "drv_l1_sdc.h"
#include "drv_l2_sd.h"
#include "gplib_print_string.h"

#if defined(__ICCARM__)
#include <stdio.h>
#endif
#include "drv_l1_gpio.h"

#if (defined _DRV_L2_SDC) && (_DRV_L2_SDC == 1)

#define SDC_L2_DEBUG	0

#if SDC_L2_DEBUG
#define SDC_L2_PRINT(...)	do{DBG_PRINT(__VA_ARGS__);}while(0)
#else
#define SDC_L2_PRINT(...)	do{}while(0)
#endif

#define SDC_FS_WRITE_PATH_USE_START_STOP	1
#define SDC_FS_READ_PATH_USE_START_STOP		1

#define SDC_FS_WRITE_PATH_USE_DMA_MSG		1			// 1 use dma message to wait, 0 use notify busy polling

// have effect only when SDC_FS_WRITE_PATH_USE_START_STOP is 1
#define SDC_FS_READ_PATH_USE_DMA_MSG	1				// 1 use dma message to wait, 0 use notify busy polling

#define SDC_USE_1BIT_MODE 	SDC_DATA_MODE /* 0: 4Bits Mode 1: 1Bit Mode */

#define SDC_TOTAL			2

#define SD_DEVICE_NUM		1

#define C_SD_L2_INIT_RETRY	2

// Timeout value(unit is ms). Maximum timeout value for card initialization is 1 second
#define C_SD_L2_CARD_INIT_TIMEOUT		(400)			// Some cards need 360 ms to response to ACMD41
#define C_SD_L2_CARD_INIT_RETRY_TIMEOUT (1000)			// Some cards need 900 ms to initialize after receiving CMD0
#define C_SD_L2_CARD_PROGRAM_TIMEOUT	(750)			// 750 ms timeout value for writing data to SD card
#if (defined _DRV_L1_TIMER) && (_DRV_L1_TIMER == 1)

// Timeout value(unit is 2.67us)
#define C_SD_L2_CARD_BUSY_TIMEOUT					(2500)
#define C_SD_L2_SINGLE_READ_CMD_COMPLETE_TIMEOUT	(560)
#define C_SD_L2_MULTI_READ_CMD_COMPLETE_TIMEOUT		(43000)//(4300)
#define C_SD_L2_SINGLE_WRITE_CMD_COMPLETE_TIMEOUT	(100 * 10)
#define C_SD_L2_MULTI_WRITE_CMD_COMPLETE_TIMEOUT	(100 * 10)
#define C_SD_L2_SINGLE_READ_DATA_COMPLETE_TIMEOUT	(100 * 10)
#define C_SD_L2_MULTI_READ_DATA_COMPLETE_TIMEOUT	(100 * 10)
#define C_SD_L2_SINGLE_WRITE_DATA_COMPLETE_TIMEOUT	(100 * 10)
#define C_SD_L2_MULTI_WRITE_DATA_COMPLETE_TIMEOUT	(100 * 10)
#define C_SD_L2_ADTC_DATA_FULL_TIMEOUT				(34000)//(3400)
#define C_SD_L2_RESP_R136_FULL_TIMEOUT				(2000)
#define C_SD_L2_RESP_R2_FULL_TIMEOUT				(180 * 10)
#define C_SD_L2_READ_CONTROLLER_STOP_TIMEOUT		(3600)
#define C_SD_L2_WRITE_CONTROLLER_STOP_TIMEOUT		(100 * 10)
#else
#define C_SD_L2_CARD_BUSY_TIMEOUT					(2500 * 10)
#define C_SD_L2_SINGLE_READ_CMD_COMPLETE_TIMEOUT	(560 * 10)
#define C_SD_L2_MULTI_READ_CMD_COMPLETE_TIMEOUT		(4300 * 10)
#define C_SD_L2_SINGLE_WRITE_CMD_COMPLETE_TIMEOUT	(100 * 100)
#define C_SD_L2_MULTI_WRITE_CMD_COMPLETE_TIMEOUT	(100 * 100)
#define C_SD_L2_SINGLE_WRITE_DATA_COMPLETE_TIMEOUT	(100 * 100)
#define C_SD_L2_MULTI_WRITE_DATA_COMPLETE_TIMEOUT	(100 * 100)
#define C_SD_L2_ADTC_DATA_FULL_TIMEOUT				(3400 * 10)
#define C_SD_L2_RESP_R136_FULL_TIMEOUT				(2000 * 10)
#define C_SD_L2_RESP_R2_FULL_TIMEOUT				(180 * 100)
#define C_SD_L2_READ_CONTROLLER_STOP_TIMEOUT		(3600 * 10)
#define C_SD_L2_WRITE_CONTROLLER_STOP_TIMEOUT		(100 * 100)
#endif
#define C_SD_L2_ACCESS_READ		1
#define C_SD_L2_ACCESS_WRITE	2

#ifndef __CS_COMPILER__
const INT8U DRVL2_sd[] = "GLB_GP-S2_0610L_sd-L2-ADS_2.0.10";
#else
const INT8U DRVL2_sd[] = "GLB_GP-S2_0610L_sd-L2-CS_2.0.10";
#endif
typedef enum
{
	SD_FLOW_IDLE	= 0,
	SD_FLOW_START,
	SD_FLOW_CONTINUE,
	SD_FLOW_STOP
} SD_FLOW_STATE_ENUM;

typedef enum
{
	SD_FLOW_NONE	= 0,
	SD_FLOW_READ,
	SD_FLOW_WRITE
} SD_FLOW_KIND_ENUM;

static SD_CARD_STATE_ENUM	sd_card_state[SDC_TOTAL] = { SD_CARD_STATE_INACTIVE, SD_CARD_STATE_INACTIVE };
static INT32U				sd_card_rca[SDC_TOTAL];		// 16 bits (31-16)
static INT32U				sd_card_csd[SDC_TOTAL][4];	// 128 bits
static INT32U				sd_card_scr[SDC_TOTAL][2];	// 64 bits
static INT32U				sd_card_cid[SDC_TOTAL][4];	// 128 bits
static INT32U				sd_card_ocr[SDC_TOTAL];		// 32 bits
static INT32U				sd_card_total_sector[SDC_TOTAL];
static INT32U				sd_card_speed[SDC_TOTAL];
static INT8U				sd_card_type[SDC_TOTAL];
static INT8U				sd_card_bus_width[SDC_TOTAL];
static INT8U				sd_card_protect[SDC_TOTAL];
static INT8U				sd_card_user[SDC_TOTAL] = { 0, 0 };

static SD_FLOW_STATE_ENUM	sd_flow_state[SDC_TOTAL] = { SD_FLOW_IDLE, SD_FLOW_IDLE };
static SD_FLOW_KIND_ENUM	sd_flow_kind[SDC_TOTAL] = { SD_FLOW_NONE, SD_FLOW_NONE };
static INT8U				sd_flow_single_sector_mode[SDC_TOTAL] = { 0, 0 };
static INT32U				sd_flow_end_sector[SDC_TOTAL] = { 0, 0 };
static INT32U				sd_flow_nr_sector[SDC_TOTAL] = { 0, 0 };
static INT32U				sd_flow_write_au_sectors[SDC_TOTAL] = { 1024, 1024 };			// 512K, 512K
static INT32U				sd_flow_read_au_sectors[SDC_TOTAL] = { 2048 * 4, 2048 * 4 };	// 4M, 4M, I think au size is for write, so read could set to larger size or no limit.

// SD Status related
ALIGN4 static INT8U			sd_card_status[SDC_TOTAL][64];	// 512 bits
static INT8U				sd_data_bus_width[SDC_TOTAL];
static INT8U				sd_secured_mode[SDC_TOTAL];
static INT8U				sd_sd_card_type[SDC_TOTAL];
static INT8U				sd_speed_class[SDC_TOTAL];
static INT8U				sd_uhs_speed_grade[SDC_TOTAL];
static INT32U				sd_uhs_au_sectors[SDC_TOTAL];
static INT16U				sd_erase_size_au[SDC_TOTAL];

extern void					drvl1_sdc_set_access_kind(INT32U device_id, INT8U kind);	// for debug only
#if _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
static OS_EVENT				*gSD_sem[SDC_TOTAL] = { NULL, NULL };
#elif _OPERATING_SYSTEM == _OS_FREERTOS
static xSemaphoreHandle		gSD_sem[SDC_TOTAL] = { NULL, NULL };
#endif
#endif
static INT32S				drvl2_sd_get_sd_info_card_status(INT32U device_id);
static void					sd_init_flow(INT32U device_id);
static INT32S				drvl2_sd_bc_command_set(INT32U device_id, INT32U command, INT32U argument);
static INT32S				drvl2_sd_bcr_ac_command_set(INT32U device_id, INT32U command, INT32U argument, INT32U response_type, INT32U *response);
static INT32S				drvl2_sd_adtc_command_set(INT32U device_id, INT32U command, INT32U rca, INT32U count, INT32U *response);
static INT32S				drvl2_v1_sd_card_initiate(INT32U device_id, INT32U timeout);
static INT32S				drvl2_v2_sd_card_initiate(INT32U device_id, INT32U timeout);
static INT32S				drvl2_mmc_card_initiate(INT32U device_id, INT32U timeout);
static INT32S				drvl2_sd_flush_base(INT32U device_id);

const static INT8U			speed_table[16] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
const static INT32U			tran_table[4] = { 10000, 100000, 1000000, 10000000 };
static INT32S				sd_sema_count[SDC_TOTAL] = { 0, 0 };

INT32U sd_wide_width_data_get_bits(INT8U *bits, INT16U total_bit, INT16U start_bit, INT16U end_bit)
{
	INT16U	start_bit_idx = (total_bit - 1) - start_bit;
	INT16U	end_bit_idx = ((total_bit - 1) - end_bit);
	INT16U	start_byte_idx;
	INT16U	end_byte_idx;
	INT16U	byte_idx;
	INT32U	value = 0;
	INT8S	bit_idx;
	INT8S	end;
	INT8S	start_byte_bit_idx;
	INT8S	end_byte_bit_idx;
	INT8S	bit_shift = start_bit - end_bit;

	if((bit_shift < 0) || (bit_shift > 31))
	{
		SDC_L2_PRINT("illegal start end bit %u, %u. must start_bit >= end_bit, (start_bit - end_bit) <= 31\r\n", start_bit, end_bit);
		return 0;
	}

	start_byte_idx = start_bit_idx >> 3;
	start_byte_bit_idx = 7 - (start_bit_idx - (start_byte_idx << 3));

	end_byte_idx = end_bit_idx >> 3;
	end_byte_bit_idx = 7 - (end_bit_idx - (end_byte_idx << 3));

	bit_idx = start_byte_bit_idx;
	end = 0;
	for(byte_idx = start_byte_idx; byte_idx <= end_byte_idx; byte_idx++)
	{
		if(byte_idx == end_byte_idx)
			end = end_byte_bit_idx;
		for(; bit_idx >= end; bit_idx--)
		{
			value |= (((INT32U) ((bits[byte_idx] >> bit_idx) & 0x1)) << bit_shift);
			bit_shift--;
			if(bit_shift < 0)
				break;
		}

		bit_idx = 7;
		if(bit_shift < 0)
			break;
	}

	return value;
}

static INT32S drvl2_sd_sem_init(INT32U device_id)
{
#if _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
	if(gSD_sem[device_id] == NULL)
		gSD_sem[device_id] = OSSemCreate(1);
#elif _OPERATING_SYSTEM == _OS_FREERTOS
	if(gSD_sem[device_id] == NULL)
		gSD_sem[device_id] = xSemaphoreCreateMutex();
#endif
#endif
	return(0);
}

static void drvl2_sd_sem_lock(INT32U device_id)
{
#if _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
	INT8U	err = NULL;
	if(gSD_sem[device_id] != NULL)
		OSSemPend(gSD_sem[device_id], 0, &err);
	else
		drvl2_sd_sem_init(device_id);

#elif _OPERATING_SYSTEM == _OS_FREERTOS
	if(gSD_sem[device_id] != NULL)
		xSemaphoreTake(gSD_sem[device_id], portMAX_DELAY);
	else
		drvl2_sd_sem_init(device_id);
#endif
	if(sd_sema_count[device_id] != 0)
		SDC_L2_PRINT("sd_sema_count not 0 before lock. %d\r\n", sd_sema_count[device_id]);
	sd_sema_count[device_id]++;
#endif
}

static void drvl2_sd_sem_unlock(INT32U device_id)
{
#if _OPERATING_SYSTEM != _OS_NONE
	sd_sema_count[device_id]--;
	if(sd_sema_count[device_id] != 0)
		SDC_L2_PRINT("sd_sema_count not 0 after unlock. %d\r\n", sd_sema_count[device_id]);

#if _OPERATING_SYSTEM == _OS_UCOS2
	OSSemPost(gSD_sem[device_id]);

#elif _OPERATING_SYSTEM == _OS_FREERTOS
	xSemaphoreGive(gSD_sem[device_id]);
#endif
#endif
}

INT32S drvl2_sd_init(INT32U device_id)
{
	INT32S	ret;
	INT32U	response;
	INT32U	count;
	INT32U	timeout;

	drvl2_sd_sem_init(device_id);
	drvl2_sd_sem_lock(device_id);

	if(sd_card_state[device_id] == SD_CARD_STATE_TRANSFER)
	{
		drvl2_sd_flush_base(device_id);

		//SDC_L2_PRINT("1 drvl2_sd_init drvl2_sd_flush done\r\n");
		drvl1_sdc_enable(device_id);

		// If card exists and in transfer state, then just return
		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD13, sd_card_rca[device_id], C_RESP_R1, &response) == 0)
		{
			if((response & 0x1E00) == 0x800)
			{	// 0x800 is transfer state
				//sd_card_user[device_id]++;
				sd_card_user[device_id] = 1;
				sd_init_flow(device_id);
				drvl2_sd_sem_unlock(device_id);
				return 0;
			}
		}
	}
	else
	{
		drvl2_sd_flush_base(device_id);

		//SDC_L2_PRINT("2 drvl2_sd_init drvl2_sd_flush done\r\n");
	}

	drvl2_sd_flush_base(device_id);

	sd_init_flow(device_id);

	sd_card_rca[device_id] = 0x0;
	sd_card_type[device_id] = C_MEDIA_STANDARD_SD_CARD;
	sd_card_total_sector[device_id] = 0;
	sd_card_speed[device_id] = 400000;	// 400K Hz
	sd_card_bus_width[device_id] = 1;
	sd_card_protect[device_id] = 0;
	sd_card_state[device_id] = SD_CARD_STATE_IDLE;

	drvl1_sdc_init(device_id);
	drvl1_sdc_enable(device_id);

	// Send 74 clock and then issue comand 0
	for(count = 0; count < C_SD_L2_INIT_RETRY; count++)
	{
		drvl1_sdc_card_init_74_cycles(device_id);
		drvl2_sd_bc_command_set(device_id, C_SD_CMD0, 0x0);
		drvl1_sdc_card_init_74_cycles(device_id);
		drvl2_sd_bc_command_set(device_id, C_SD_CMD0, 0x0);
		drvl1_sdc_card_init_74_cycles(device_id);

		if(count == 0)
		{
			timeout = C_SD_L2_CARD_INIT_TIMEOUT;
		}
		else
		{
			timeout = C_SD_L2_CARD_INIT_RETRY_TIMEOUT;
		}

		// Issue command 8
		ret = drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD8, 0x000001AA, C_RESP_R7, &response);

		// If the card responses to command 8
		if(ret == 0)
		{	// Ver 2.0 standard SD card or SDHC card
			if(!(response & 0x100))
			{
				// If response is not valid, it is an unusable card
				sd_card_state[device_id] = SD_CARD_STATE_INACTIVE;
				drvl2_sd_sem_unlock(device_id);
				SDC_L2_PRINT("SDERR 1\r\n");
				return -1;
			}

			if(drvl2_v2_sd_card_initiate(device_id, timeout) == 0)
			{
				break;
			}
		}
		else
		{	// If the card doesn't response to command 8, it is a ver 1.x SD card or MMC
			if(drvl2_v1_sd_card_initiate(device_id, timeout) == 0)
			{
				break;
			}

			if(sd_card_type[device_id] == C_MEDIA_MMC_CARD)
			{
				if(drvl2_mmc_card_initiate(device_id, timeout) == 0)
				{
					break;
				}
			}

			// if card type is SDHC but fail to response to CMD8, we have to run the initialization process again
		}

#if _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
		OSTimeDly(1);
#elif _OPERATING_SYSTEM == _OS_FREERTOS
		vTaskDelay(1);
#endif
#endif
	}

	if(count == C_SD_L2_INIT_RETRY)
	{
		drvl2_sd_sem_unlock(device_id);

		//SDC_L2_PRINT("SDERR 2\r\n");
		return -1;
	}

	sd_card_state[device_id] = SD_CARD_STATE_READY;

	// Send command 2
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD2, 0x0, C_RESP_R2, &sd_card_cid[device_id][0]))
	{
		drvl2_sd_sem_unlock(device_id);
		SDC_L2_PRINT("SDERR 3\r\n");
		return -1;
	}

	sd_card_state[device_id] = SD_CARD_STATE_IDENTIFICATION;

	// Send command 3
	if((sd_card_type[device_id] != C_MEDIA_MMC_CARD) && (sd_card_type[device_id] != C_MEDIA_MMCHC_CARD))
	{
		// Send CMD3 and read new RCA, SD will generate RCA itself
		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD3, 0x0, C_RESP_R6, &response))
		{
			drvl2_sd_sem_unlock(device_id);
			SDC_L2_PRINT("SDERR 4\r\n");
			return -1;
		}

		sd_card_rca[device_id] = response & 0xFFFF0000;
	}
	else
	{
		// Send CMD3 to set a new RCA to MMC card
		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD3, 0xFFFF0000, C_RESP_R6, &response))
		{
			drvl2_sd_sem_unlock(device_id);
			SDC_L2_PRINT("SDERR 5\r\n");
			return -1;
		}

		sd_card_rca[device_id] = 0xFFFF0000;
	}

	sd_card_state[device_id] = SD_CARD_STATE_STANDBY;

	// Set bus width and clock speed
	ret = drvl2_sd_bus_clock_set(device_id, SDC_BUS_CLOCK);
	if(ret < 0)
	{
		SDC_L2_PRINT("SDERR 6\r\n");
		ret = drvl2_sd_bus_clock_set(device_id, SDC_BUS_CLOCK >> 1);
	}

	if(ret == 0)
		//sd_card_user[device_id]++;
		sd_card_user[device_id] = 1;
	else
		SDC_L2_PRINT("SDERR 7\r\n");
	{
		INT32U	sd_clock_rate, sd_souce_clock_rate, sd_clock_div;

		drvl1_sdc_running_clock_rate_get(device_id, &sd_clock_rate, &sd_souce_clock_rate, &sd_clock_div);
		SDC_L2_PRINT("sd[%u] clock rate=%u, root rate=%u divider=%u\r\n", device_id, sd_clock_rate, sd_souce_clock_rate, sd_clock_div);
	}

	drvl2_sd_get_sd_info_card_status(device_id);
	if(sd_card_total_sector[device_id] < 4 * 2048)
		sd_flow_read_au_sectors[device_id] = (sd_card_total_sector[device_id] >> 11) << 11; // set read au to mega sector of capacity
	drvl2_sd_sem_unlock(device_id);
	return ret;
}

static void drvl2_sd_set_speed_bus(INT32U device_id)
{
	drvl1_sdc_clock_set(device_id, sd_card_speed[device_id]);
	drvl1_sdc_bus_width_set(device_id, sd_card_bus_width[device_id]);						// Set bus width to 4 bits
}

static INT32S drvl2_sd_bc_command_set(INT32U device_id, INT32U command, INT32U argument)
{
	return drvl1_sdc_command_send(device_id, command, argument);
}

static INT32S drvl2_sd_bcr_ac_command_set(INT32U device_id, INT32U command, INT32U argument, INT32U response_type, INT32U *response)
{
	INT8U	i;

	if(drvl1_sdc_command_send(device_id, command, argument))
	{
		//SDC_L2_PRINT("SDERR 31=0x%08x, 0x%08x\r\n", command, argument);
		return -1;
	}

	switch(response_type)
	{
	case C_RESP_R1:
	case C_RESP_R1B:
	case C_RESP_R3:
	case C_RESP_R6:
		return drvl1_sdc_response_get(device_id, response, C_SD_L2_RESP_R136_FULL_TIMEOUT);

	case C_RESP_R2:
		for(i = 0; i < 4; i++)
		{
			if(drvl1_sdc_response_get(device_id, response, C_SD_L2_RESP_R2_FULL_TIMEOUT))
			{
				SDC_L2_PRINT("SDERR 32\r\n");
				return -1;
			}

			response++;
		}

	case C_RESP_R0:
	default:
		break;
	}

	return 0;
}

static INT32S drvl2_sd_adtc_command_set(INT32U device_id, INT32U command, INT32U rca, INT32U count, INT32U *response)
{
	// Clear SD RX data register before read command is issued
	drvl1_sdc_clear_rx_data_register(device_id);

	if(drvl1_sdc_command_send(device_id, command, rca))
	{
		return -1;
	}

	while(count)
	{
		if(drvl1_sdc_data_get(device_id, response, C_SD_L2_ADTC_DATA_FULL_TIMEOUT))
		{
			return -1;
		}

		response++;
		count--;
	}

	return 0;
}

static INT32S drvl2_v1_sd_card_initiate(INT32U device_id, INT32U timeout)
{
	INT32S	ret;
	INT32U	response;
	INT32U	timer;

#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
	timer = (INT32U) sw_timer_get_counter_L();
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
	timer = OSTimeGet();	// 10ms per tick
#elif _OPERATING_SYSTEM == _OS_FREERTOS
	timer = xTaskGetTickCount();
#endif
#else
	timer = 0;
#endif
	do
	{
		// Send ACMD41 with HCS=0 until card is ready or timeout
		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD55, 0x0, C_RESP_R1, &response))
		{
			// If CMD55 timeout occurs, maybe it is a MMC card
			sd_card_type[device_id] = C_MEDIA_MMC_CARD;

			return -1;
		}

		ret = drvl2_sd_bcr_ac_command_set(device_id, C_SD_ACMD41, 0x00200000, C_RESP_R3, &sd_card_ocr[device_id]);
		if(ret)
		{
#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
			if((sw_timer_get_counter_L() - timer) > timeout)
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
				if((OSTimeGet() - timer) * 10 > timeout)
#elif _OPERATING_SYSTEM == _OS_FREERTOS
					if((xTaskGetTickCount() - timer) > timeout)
#endif
#else
						if(++timer > timeout)
#endif
						{
							// If card timeout occurs, maybe it is a MMC card
							sd_card_type[device_id] = C_MEDIA_MMC_CARD;

							return -1;
						}
		}
		else
		if(!(sd_card_ocr[device_id] & 0x80000000))
		{
#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
			if((sw_timer_get_counter_L() - timer) > timeout)
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
				if((OSTimeGet() - timer) * 10 > timeout)
#elif _OPERATING_SYSTEM == _OS_FREERTOS
					if((xTaskGetTickCount() - timer) > timeout)
#endif
#else
						if(++timer > timeout)
#endif
						{
							// If card busy timeout occurs, maybe it is a SDHC card
							sd_card_type[device_id] = C_MEDIA_SDHC_CARD;

							return -1;
						}
		}
		else
		{					// It is a Ver1.X standard SD card
			sd_card_type[device_id] = C_MEDIA_STANDARD_SD_CARD;
			break;
		}
	} while(1);

	return 0;
}

static INT32S drvl2_v2_sd_card_initiate(INT32U device_id, INT32U timeout)
{
	INT32S	ret;
	INT32U	response;
	INT32U	timer;

#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
	timer = (INT32U) sw_timer_get_counter_L();
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
	timer = OSTimeGet();	// 10ms per tick
#elif _OPERATING_SYSTEM == _OS_FREERTOS
	timer = xTaskGetTickCount();
#endif
#else
	timer = 0;
#endif
	do
	{
		// Send ACMD41 with HCS=1 until card is ready or timeout
		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD55, 0x0, C_RESP_R1, &response))
		{
			return -1;
		}

		ret = drvl2_sd_bcr_ac_command_set(device_id, C_SD_ACMD41, 0x40200000, C_RESP_R3, &sd_card_ocr[device_id]);
		if(ret || !(sd_card_ocr[device_id] & 0x80000000))
		{
			// Maximum timeout value for card initialization is 1 second
#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
			if((sw_timer_get_counter_L() - timer) > timeout)
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
				if((OSTimeGet() - timer) * 10 > timeout)
#elif _OPERATING_SYSTEM == _OS_FREERTOS
					if((xTaskGetTickCount() - timer) > timeout)
#endif
#else
						if(++timer > timeout)
#endif
						{
							// If card timeout occurs, it is an unusable card
							return -1;
						}
		}
		else
		{
			if(sd_card_ocr[device_id] & 0x40000000)
			{				// If CCS in sd_card_ocr is 1, it is a Ver2.0 SDHC card
				sd_card_type[device_id] = C_MEDIA_SDHC_CARD;
			}
			else
			{				// If CCS in sd_card_ocr is 0, it is a Ver2.0 standard SD card
				sd_card_type[device_id] = C_MEDIA_STANDARD_SD_CARD;
			}

			break;
		}
	} while(1);

	return 0;
}

static INT32S drvl2_mmc_card_initiate(INT32U device_id, INT32U timeout)
{
	INT32S	ret;
	INT32U	response;
	INT32U	timer;

	// Start MMC initialization process
#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
	timer = (INT32U) sw_timer_get_counter_L();
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
	timer = OSTimeGet();	// 10ms per tick
#elif _OPERATING_SYSTEM == _OS_FREERTOS
	timer = xTaskGetTickCount();
#endif
#else
	timer = 0;
#endif
	do
	{
		// Send CMD1 with voltage range set until card is ready or timeout
		ret = drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD1, 0x40FF8000, C_RESP_R3, &response);
		if(ret || !(response & 0x80000000))
		{
#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
			if((sw_timer_get_counter_L() - timer) > timeout)
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
				if((OSTimeGet() - timer) * 10 > timeout)
#elif _OPERATING_SYSTEM == _OS_FREERTOS
					if((xTaskGetTickCount() - timer) > timeout)
#endif
#else
						if(++timer > timeout)
#endif
						{
							// If card timeout occurs, it is an unusable card
							sd_card_state[device_id] = SD_CARD_STATE_INACTIVE;

							return -1;
						}
		}
		else
		{
			// Check whether voltage is acceptable
			if(!(response & 0x00FF8000))
			{
				// If response is not valid, it is an unusable card
				sd_card_state[device_id] = SD_CARD_STATE_INACTIVE;

				return -1;
			}

			sd_card_type[device_id] = C_MEDIA_MMC_CARD;
			break;
		}
	} while(1);

	// MMC HC card
	if(response & 0x40000000)
		sd_card_type[device_id] = C_MEDIA_MMCHC_CARD;
	return 0;
}

static INT32U drvl2_sd_despeed(INT32U device_id)
{
	INT32U	time_value = (sd_card_csd[device_id][0] & 0x00000078) >> 3;
	INT32U	tran_unit = sd_card_csd[device_id][0] & 0x00000007;

	if((time_value >= sizeof(speed_table)) || (tran_unit >= sizeof(tran_table)))
		return 0;
	else
		return speed_table[time_value] * tran_table[tran_unit];
}

// get the SD STATUS to know features of SD, sd_card_status_buf must at least 64 byte buffer
static INT32S drvl2_sd_get_sd_card_status(INT32U device_id)
{
	INT32U	response;
	INT32S	ret;

	// Send ACMD13 to read 512-bits SD Status, must in transfer state to use this command.
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD55, sd_card_rca[device_id], C_RESP_R1, &response) == 0)
	{
		drvl1_sdc_block_len_set(device_id, 64);
		if(drvl2_sd_adtc_command_set(device_id, C_SD_ACMD13, sd_card_rca[device_id], 16, (INT32U *) (&sd_card_status[device_id][0])) == 0)
		{
			ret = 0;
#if 0				// DEBUG CODE
			{
				INT32U	count;

				SDC_L2_PRINT("SD Status:\r\n");
				for(count = 0; count < 64; count++)
					SDC_L2_PRINT("%02x", sd_card_status[device_id][count]);
				SDC_L2_PRINT("\r\n");
			}

#endif
		}
		else
			ret = -2;
		drvl1_sdc_block_len_set(device_id, C_SD_SECTOR_SIZE);
	}
	else
		ret = -1;

	return ret;
}

static INT32U drvl2_sd_get_info_au_sector(INT32U device_id)
{
	INT8U	au_idx; // 4 bit
	INT32U	au_sector = 0;

	// au_size 431:428
	au_idx = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 431, 428);

	//SDC_L2_PRINT("au_idx=%u\r\n", au_idx);
	if(au_idx >= 1)
		au_sector = 1 << (4 + au_idx);

	return au_sector;
}

static INT8U drvl2_sd_get_info_speed_class(INT32U device_id)
{
	INT8U	speed_class_idx;		// 4 bit
	INT8U	speed_class = 0;

	speed_class_idx = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 447, 440);
	if(speed_class_idx > 4)
	{
		SDC_L2_PRINT("unknown speed class %u\r\n", speed_class_idx);
		return 255;
	}

	if(speed_class_idx == 4)
		speed_class = 10;
	else
		speed_class = speed_class_idx * 2;

	return speed_class;
}

static INT8U drvl2_sd_get_info_bus_width(INT32U device_id)
{
	INT8U	bus_width_idx;			// 2 bit
	INT8U	bus_width = 1;

	bus_width_idx = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 511, 510);
	if(bus_width_idx == 0)
		bus_width = 1;
	else
	if(bus_width_idx == 2)
		bus_width = 4;
	else
		SDC_L2_PRINT("unknown bus width %u\r\n", bus_width_idx);

	return bus_width;
}

static INT8U drvl2_sd_get_info_secure_mode(INT32U device_id)
{
	INT8U	sd_secured_mode;		// 1 bit
	sd_secured_mode = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 509, 509);

	return sd_secured_mode;
}

static INT8U drvl2_sd_get_info_card_type(INT32U device_id)
{
	INT16U	sd_sd_card_type_idx;	// 16 bit
	INT8U	sd_sd_card_type = SD_CARD_TYPE_RW;

	sd_sd_card_type_idx = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 495, 480);
	if(sd_sd_card_type_idx > 2)
		SDC_L2_PRINT("unknown card type %u\r\n", sd_sd_card_type_idx);
	else
		sd_sd_card_type = sd_sd_card_type_idx;

	return sd_sd_card_type;
}

static INT32U drvl2_sd_get_info_erase_size_au(INT32U device_id)
{
	INT16U	erase_size_au = 0;

	// erase_size 423:408
	erase_size_au = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 423, 408);

	return erase_size_au;
}

static INT8U drvl2_sd_get_info_uhs_speed_grade(INT32U device_id)
{
	INT8U	uhs_speed_grade_idx;	// 4 bit
	INT8U	uhs_speed_grade = SD_CARD_UHS_SPEED_GRADE_0;

	// 399:396 UHS_SPEED_GRADE
	uhs_speed_grade_idx = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 399, 396);
	if(uhs_speed_grade_idx == 0)
		uhs_speed_grade = SD_CARD_UHS_SPEED_GRADE_0;
	else
	if(uhs_speed_grade_idx == 1)
		uhs_speed_grade = SD_CARD_UHS_SPEED_GRADE_1;
	else
	if(uhs_speed_grade_idx == 3)
		uhs_speed_grade = SD_CARD_UHS_SPEED_GRADE_3;
	else
		SDC_L2_PRINT("unknown uhs speed grade %u\r\n", uhs_speed_grade_idx);

	return uhs_speed_grade;
}

static INT32U drvl2_sd_get_info_uhs_au_sector(INT32U device_id)
{
	INT8U	uhs_au_idx;				// 4 bit
	INT32U	uhs_au_sector = 0;

	// 395:392 UHS_AU_SIZE
	uhs_au_idx = sd_wide_width_data_get_bits(&sd_card_status[device_id][0], 512, 395, 392);

	//SDC_L2_PRINT("uhs_au_idx=%u\r\n", uhs_au_idx);
	if(uhs_au_idx >= 7)
		uhs_au_sector = 1 << (4 + uhs_au_idx);

	return uhs_au_sector;
}

// get the SD STATUS info of SD and explain each field of it
static INT32S drvl2_sd_get_sd_info_card_status(INT32U device_id)
{
	if(drvl2_sd_get_sd_card_status(device_id))
		return -1;

	sd_data_bus_width[device_id] = drvl2_sd_get_info_bus_width(device_id);
	SDC_L2_PRINT("sd_data_bus_width=%u\r\n", sd_data_bus_width[device_id]);

	sd_secured_mode[device_id] = drvl2_sd_get_info_secure_mode(device_id);
	SDC_L2_PRINT("sd_secured_mode=%u\r\n", sd_secured_mode[device_id]);

	// 508:502 Reserved for Security Functions (Refer to Part 3 Security Specification)
	// 501:496 reserved
	sd_sd_card_type[device_id] = drvl2_sd_get_info_card_type(device_id);
	SDC_L2_PRINT("sd_sd_card_type=%u\r\n", sd_sd_card_type[device_id]);

	// size_of_protected_area 479:448, 32 bit
	sd_speed_class[device_id] = drvl2_sd_get_info_speed_class(device_id);
	SDC_L2_PRINT("sd_speed_class=%u\r\n", sd_speed_class[device_id]);

	// performance_move 439:432
	// au_size 431:428
	sd_flow_write_au_sectors[device_id] = drvl2_sd_get_info_au_sector(device_id);
	SDC_L2_PRINT("sd_flow_write_au_sectors=%u\r\n", sd_flow_write_au_sectors[device_id]);

	// reserve 427:424
	// erase_size 423:408
	sd_erase_size_au[device_id] = drvl2_sd_get_info_erase_size_au(device_id);
	SDC_L2_PRINT("sd_erase_size_au=%u\r\n", sd_erase_size_au[device_id]);

	// 407:402 ERASE_TIMEOUT
	// 401:400 ERASE_OFFSET
	// 399:396 UHS_SPEED_GRADE
	sd_uhs_speed_grade[device_id] = drvl2_sd_get_info_uhs_speed_grade(device_id);
	SDC_L2_PRINT("sd_uhs_speed_grade=%u\r\n", sd_uhs_speed_grade[device_id]);

	// 395:392 UHS_AU_SIZE
	sd_uhs_au_sectors[device_id] = drvl2_sd_get_info_uhs_au_sector(device_id);
	SDC_L2_PRINT("sd_uhs_au_sectors=%u\r\n", sd_uhs_au_sectors[device_id]);

	// 391:312 reserved
	// 311:0 reserved for manufacturer
	return 0;
}

static INT32S drvl2_sd_bus_clock_set_sdcard(INT32U device_id, INT32U limit_speed)
{
	INT32U	response;
	INT32U	c_size, mult, block_len;
	INT32U	max_speed;
	INT32U	switch_function_data[16];	// 512 bits
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD7, sd_card_rca[device_id], C_RESP_R1B, &response))
	{
		SDC_L2_PRINT("SDERR 20\r\n");
		return -1;
	}

	// Send ACMD51 to read 64-bits SD configuration register(SCR)
	if(drvl1_sdc_block_len_set(device_id, 8))
	{
		SDC_L2_PRINT("SDERR 21\r\n");
		return -1;
	}

	// Send ACMD51 to read 64-bits SD configuration register(SCR)
	if
	(
		drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD55, sd_card_rca[device_id], C_RESP_R1, &response)
	||	drvl2_sd_adtc_command_set(device_id, C_SD_ACMD51, sd_card_rca[device_id], 2, &sd_card_scr[device_id][0])
	)
	{
		SDC_L2_PRINT("SDERR 22\r\n");
		return -1;
	}

	// Reset block length to C_SD_SECTOR_SIZE bytes
	if(drvl1_sdc_block_len_set(device_id, C_SD_SECTOR_SIZE))
	{
		SDC_L2_PRINT("SDERR 23\r\n");
		return -1;
	}

	// Check limit clock and SD spec version
	if((limit_speed > 25000000) && (sd_card_scr[device_id][0] & 0x0F) > 1)
	{
		// Set block length to 64 bytes so that we can read status data of CMD6
		drvl1_sdc_block_len_set(device_id, 64);

		// Send ACMD6 to set bus width to 1 bit mode
		if(sd_card_bus_width[device_id] == 4)
		{
			drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD55, sd_card_rca[device_id], C_RESP_R1, &response);
			drvl2_sd_bcr_ac_command_set(device_id, C_SD_ACMD6, 0x0, C_RESP_R1, &response);
			drvl1_sdc_bus_width_set(device_id, 1);
		}

		if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD6, 0x00FFFF01, 16, &switch_function_data[0]) == 0)
		{
			// Check whether card supports high-speed mode
			if((switch_function_data[3] & 0x00000300) == 0x00000300)
			{
				drvl2_sd_adtc_command_set(device_id, C_SD_CMD6, 0x80FFFF01, 16, &switch_function_data[0]);
			}
		}

		// Restore sector length
		drvl1_sdc_block_len_set(device_id, C_SD_SECTOR_SIZE);
	}

	if(sd_card_scr[device_id][0] & 0x00000400)
	{
		// Check whether this SD card supports 4-bits bus width

#if (SDC_USE_1BIT_MODE == 1)
		// some fpga board such as s2 board because signal is bad, could not use 4 bit board
		SDC_L2_PRINT("SD USE 1 BIT MODE !\r\n");
#else

		sd_card_bus_width[device_id] = 4;

		// Send ACMD6 to set the card to 4-bit bus width
		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD55, sd_card_rca[device_id], C_RESP_R1, &response) || drvl2_sd_bcr_ac_command_set(device_id, C_SD_ACMD6, 0x2, C_RESP_R1, &response))
		{
			SDC_L2_PRINT("SDERR 24\r\n");
			return -1;
		}

		drvl1_sdc_bus_width_set(device_id, 4);	// Set bus width to 4 bits


#endif
	}

	// Switch back to standby state
	drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD7_R0, 0x0, C_RESP_R0, &response);

	drv_msec_wait(1);	// williamyeo, fix timeout that happen at C_SD_CMD9

	// Send CMD9 and read CSD Register
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD9, sd_card_rca[device_id], C_RESP_R2, &sd_card_csd[device_id][0]))
	{
		SDC_L2_PRINT("SDERR 25\r\n");
		return -1;
	}

	// Calculate Totoal Memory Size
	if(sd_card_type[device_id] == C_MEDIA_SDHC_CARD)
	{
		c_size = ((sd_card_csd[device_id][2] >> 16) & 0x0000FFFF) + ((sd_card_csd[device_id][1] & 0x0000003F) << 16);
		sd_card_total_sector[device_id] = (c_size + 1) << 10;
		SDC_L2_PRINT("SDHC_CARD. c_size=%d total_sector=%d\r\n", c_size, sd_card_total_sector[device_id]);
	}
	else
	{
		block_len = (sd_card_csd[device_id][1] >> 16) & 0xF;
		c_size = ((sd_card_csd[device_id][1] & 0x3FF) << 2) | ((sd_card_csd[device_id][2] >> 30) & 0x3);
		mult = (sd_card_csd[device_id][2] >> 15) & 0x7;
		sd_card_total_sector[device_id] = (c_size + 1) << (mult + 2 + block_len - 9);
		SDC_L2_PRINT("SD_CARD. c_size=%d total_sector=%d block_len=%d mult=%d\r\n", c_size, sd_card_total_sector[device_id], block_len, mult);
	}

	max_speed = drvl2_sd_despeed(device_id);
	if(max_speed == 0)
	{
		SDC_L2_PRINT("SDERR 26\r\n");
		return -1;
	}

	if(max_speed > limit_speed)
	{
		max_speed = limit_speed;
	}

	sd_card_speed[device_id] = max_speed;
	if(drvl1_sdc_clock_set(device_id, max_speed))
	{
		SDC_L2_PRINT("SDERR 27\r\n");
		return -1;
	}

	// Change to transfer state
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD7, sd_card_rca[device_id], C_RESP_R1B, &response))
	{
		// sdc speed back to 400k
		drvl1_sdc_clock_set(device_id, 400000);
		SDC_L2_PRINT("SDERR 28\r\n");
		return -1;
	}

	sd_card_state[device_id] = SD_CARD_STATE_TRANSFER;
	return 0;
}

static INT32S drvl2_sd_bus_clock_set_mmc(INT32U device_id, INT32U limit_speed)
{
	INT32U	response;
	INT32U	c_size, mult, block_len;
	INT32U	max_speed;
	INT32U	SPEC_VAR;

	// Send CMD9 and read CSD Register
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD9, sd_card_rca[device_id], C_RESP_R2, &sd_card_csd[device_id][0]))
	{
		return -1;
	}

	SPEC_VAR = (sd_card_csd[device_id][0] & 0x3C000000) >> 26;
	max_speed = drvl2_sd_despeed(device_id);
	if(max_speed == 0)
		return -1;

	// Change to transfer state
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD7, sd_card_rca[device_id], C_RESP_R1B, &response))
	{
		// sdc speed back to 400k
		drvl1_sdc_clock_set(device_id, 400000);
		return -1;
	}

	sd_card_state[device_id] = SD_CARD_STATE_TRANSFER;

	// ----- Only spec. 4.0 or latter can support SWITCH function -----
	if(SPEC_VAR >= 4)
	{
		//----- Setup MMC bus width 4 bit -----
		if(drvl2_sd_bcr_ac_command_set(device_id, C_MMC_CMD6, 0x03b70100, C_RESP_R1B, &response))
		{
			return -1;
		}

		if((response & 0x08) == 0)
		{
			sd_card_bus_width[device_id] = 4;
			drvl1_sdc_bus_width_set(device_id, 4);	// Set bus width to 4 bits
			SDC_L2_PRINT("MMC use 4 bit\r\n");
		}

		//----- Setup MMC to high speed mode -----
		if(limit_speed > 25000000)
		{
			if(drvl2_sd_bcr_ac_command_set(device_id, C_MMC_CMD6, 0x03b90100, C_RESP_R1B, &response))
			{
				return -1;
			}

			if((response & 0x08) == 0)
			{
				max_speed = 52000000;
				SDC_L2_PRINT("MMC max speed is 52M\r\n");
			}
		}
	}

	if(max_speed > limit_speed)
	{
		max_speed = limit_speed;
	}

	sd_card_speed[device_id] = max_speed;
	if(drvl1_sdc_clock_set(device_id, max_speed))
	{
		return -1;
	}

	if(sd_card_type[device_id] == C_MEDIA_MMCHC_CARD)
	{
		INT32U	buf[128] = { 0 };

		if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD8 | C_SDC_CMD_WITH_DATA, 0, 128, buf))
		{
			return -1;
		}

		sd_card_total_sector[device_id] = buf[53];
	}
	else
	{
		block_len = (sd_card_csd[device_id][1] >> 16) & 0xF;
		c_size = ((sd_card_csd[device_id][1] & 0x3FF) << 2) | ((sd_card_csd[device_id][2] >> 30) & 0x3);
		mult = (sd_card_csd[device_id][2] >> 15) & 0x7;
		sd_card_total_sector[device_id] = (c_size + 1) << (mult + 2 + block_len - 9);
	}

	return 0;
}

INT32S drvl2_sd_bus_clock_set(INT32U device_id, INT32U limit_speed)
{
	INT32U	response;

	// Make sure that card is ready and in standby state
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD13, sd_card_rca[device_id], C_RESP_R1, &response))
	{
		SDC_L2_PRINT("SDERR 10\r\n");
		return -1;
	}

	response &= 0x1E00;

	if(response != 0x0600 && response != 0x0800)
	{					// 0x0600 is standby state, 0x800 is transfer state
		SDC_L2_PRINT("SDERR 11\r\n");
		return -1;
	}

	if(response == 0x0800)
	{
		// Switch from transfer state to standby state
		SDC_L2_PRINT("SD standy\r\n");
		drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD7_R0, 0x0, C_RESP_R0, &response);
	}

	if(sd_card_type[device_id] == C_MEDIA_SDHC_CARD || sd_card_type[device_id] == C_MEDIA_STANDARD_SD_CARD)
		return drvl2_sd_bus_clock_set_sdcard(device_id, limit_speed);
	else
		return drvl2_sd_bus_clock_set_mmc(device_id, limit_speed);
}

void drvl2_sd_card_info_get(INT32U device_id, SD_CARD_INFO_STRUCT *sd_info)
{
	INT8U	i;

	sd_info->rca = (sd_card_rca[device_id] >> 16) & 0xFFFF;
	for(i = 0; i < 4; i++)
	{
		sd_info->csd[i] = sd_card_csd[device_id][i];
	}

	for(i = 0; i < 2; i++)
	{
		sd_info->scr[i] = sd_card_scr[device_id][i];
	}

	for(i = 0; i < 4; i++)
	{
		sd_info->cid[i] = sd_card_cid[device_id][i];
	}

	sd_info->ocr = sd_card_ocr[device_id];
}

INT8U drvl2_sd_card_protect_get(INT32U device_id)
{
	return sd_card_protect[device_id];
}

void drvl2_sd_card_protect_set(INT32U device_id, INT8U value)
{
	sd_card_protect[device_id] = value;
}

INT32U drvl2_sd_sector_number_get(INT32U device_id)
{
	return sd_card_total_sector[device_id];
}

static INT32S drvl2_sd_card_busy_wait(INT32U device_id, INT32U timeout)
{
	INT32U	timer;

	// Wait operation complete and back to transfer state
#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
	timer = (INT32U) sw_timer_get_counter_L();
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
	timer = OSTimeGet();
#elif _OPERATING_SYSTEM == _OS_FREERTOS
	timer = xTaskGetTickCount();
#endif
#else
	timer = 0;
#endif
	do
	{
		drvl1_sdc_card_init_74_cycles(device_id);
		if(drvl1_sdc_card_busy_wait(device_id, 0))
		{
#if (defined _DRV_L1_SW_TIMER) && (_DRV_L1_SW_TIMER == 1)
			if((sw_timer_get_counter_L() - timer) > (timeout))
			{
#elif _OPERATING_SYSTEM != _OS_NONE
#if _OPERATING_SYSTEM == _OS_UCOS2
				if((OSTimeGet() - timer) > (timeout / 10))
#elif _OPERATING_SYSTEM == _OS_FREERTOS
					if((xTaskGetTickCount() - timer) > timeout)
#endif
#else
						if(++timer > timeout)
#endif
						{
							return -1;
						}
			}
			else
			{
				break;
			}
		}
		while(1);

		return 0;
	}

#if (SDC_FS_READ_PATH_USE_START_STOP == 1)
	INT32S drvl2_sd_read(INT32U device_id, INT32U start_sector, INT32U *buffer, INT32U sector_count)
{
	INT32S	ret;

	drvl2_sd_sem_lock(device_id);

	ret = drvl2_sd_read_start(device_id, start_sector, sector_count);
	if(ret != 0)
	{
		drvl2_sd_sem_unlock(device_id);
		return ret;
	}

	ret = drvl2_sd_read_sector(device_id, buffer, sector_count, SDC_FS_READ_PATH_USE_DMA_MSG);
	if(ret != 0)
	{
		drvl2_sd_sem_unlock(device_id);
		return ret;
	}

	ret = drvl2_sd_read_stop(device_id);
	if(ret != 0)
	{
		drvl2_sd_sem_unlock(device_id);
		return ret;
	}

	drvl2_sd_sem_unlock(device_id);

	return ret;
}

#else
INT32S drvl2_sd_read(INT32U device_id, INT32U start_sector, INT32U *buffer, INT32U sector_count)
{
	volatile sdReg_t	*sd = (sdReg_t *) SetSDBase(device_id);
	INT32U				response;
	INT32S				ret;

	drvl2_sd_sem_lock(device_id);

	drvl1_sdc_set_access_kind(device_id, C_SD_L2_ACCESS_READ);

	if(sd_card_state[device_id] != SD_CARD_STATE_TRANSFER)
	{
		drvl2_sd_sem_unlock(device_id);
		return -1;
	}

	drvl2_sd_set_speed_bus(device_id);
	if(drvl2_sd_card_busy_wait(device_id, C_SD_L2_CARD_BUSY_TIMEOUT))
	{
		drvl2_sd_sem_unlock(device_id);
		return -1;
	}

#if 0
	if(drvl2_sd_bcr_ac_command_set(C_SD_CMD13, sd_card_rca, C_RESP_R1, &response) == 0)
	{
		// Check whether card is in transfer state
		if(!(response & 0x100))
		{
			drvl2_sd_sem_unlock(device_id);
			return -1;
		}
	}

#endif

	// Clear SD RX data register before read command is issued
	drvl1_sdc_clear_rx_data_register(device_id);

	if(sector_count == 1)
	{
		if((sd_card_type[device_id] == C_MEDIA_SDHC_CARD) || (sd_card_type[device_id] == C_MEDIA_MMCHC_CARD))
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD17, start_sector, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}
		else
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD17, start_sector << 9, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}

		if(drvl1_sdc_command_complete_wait(device_id, C_SD_L2_SINGLE_READ_CMD_COMPLETE_TIMEOUT))
		{
			SDC_L2_PRINT("1 drvl1_sdc_command_complete_wait error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
			ret = -1;
		}

		sd_card_state[device_id] = SD_CARD_STATE_SENDING_DATA;

		ret = drvl1_sdc_read_data_by_dma(device_id, buffer, sector_count, NULL);
		if(ret != 0)
		{
			SDC_L2_PRINT("1 drvl1_sdc_read_data_by_dma error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
		}

		if(drvl1_sdc_data_complete_wait(device_id, C_SD_L2_SINGLE_READ_DATA_COMPLETE_TIMEOUT))
		{
			SDC_L2_PRINT("1 read data_complete_wait fail[%d]. status=0x%08x start=%d, sector_count=%d\r\n", device_id, sd->Status, start_sector, sector_count);
			ret = -1;
		}

		if(drvl1_sdc_data_crc_status_get(device_id))
		{
			ret = -1;
			SDC_L2_PRINT("1 drvl2_sd_read crc error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
		}
	}
	else
	{
		if((sd_card_type[device_id] == C_MEDIA_SDHC_CARD) || (sd_card_type[device_id] == C_MEDIA_MMCHC_CARD))
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD18, start_sector, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}
		else
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD18, start_sector << 9, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}

		if(drvl1_sdc_command_complete_wait(device_id, C_SD_L2_MULTI_READ_CMD_COMPLETE_TIMEOUT))
		{
			SDC_L2_PRINT("2 drvl1_sdc_command_complete_wait error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
			ret = -1;
		}

		sd_card_state[device_id] = SD_CARD_STATE_SENDING_DATA;

		ret = drvl1_sdc_read_data_by_dma(device_id, buffer, sector_count, NULL);
		if(ret != 0)
		{
			SDC_L2_PRINT("2 drvl1_sdc_read_data_by_dma error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
		}

		if(drvl1_sdc_data_complete_wait(device_id, C_SD_L2_MULTI_READ_DATA_COMPLETE_TIMEOUT))
		{
			SDC_L2_PRINT("2 read data_complete_wait fail[%d]. status=0x%08x start=%d, sector_count=%d\r\n", device_id, sd->Status, start_sector, sector_count);
			ret = -1;
		}

		if(drvl1_sdc_data_crc_status_get(device_id))
		{
			SDC_L2_PRINT("2 drvl2_sd_read crc error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
			ret = -1;
		}

		if(drvl1_sdc_stop_controller(device_id, C_SD_L2_READ_CONTROLLER_STOP_TIMEOUT))
		{
			ret = -1;
		}

		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD12, 0x0, C_RESP_R1B, &response))
		{
			SDC_L2_PRINT("2 sd read stop error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
			ret = -1;	// some non brand card will happen read stop command response crc error

			// using 49.5M sd clock will always happen read data crc error
			// using 47.25M happen some data crc error, retry could pass, but alsmost always happen
			// read stop command response crc error. Must down untill 41.25M to pass.
		}
	}

	sd_card_state[device_id] = SD_CARD_STATE_TRANSFER;
	drvl2_sd_sem_unlock(device_id);
	return ret;
}

#endif
#if (SDC_FS_WRITE_PATH_USE_START_STOP == 1)
INT32S drvl2_sd_write(INT32U device_id, INT32U start_sector, INT32U *buffer, INT32U sector_count)
{
	INT32S	ret;

	drvl2_sd_sem_lock(device_id);

	ret = drvl2_sd_write_start(device_id, start_sector, sector_count);
	if(ret != 0)
	{
		drvl2_sd_sem_unlock(device_id);
		return ret;
	}

	ret = drvl2_sd_write_sector(device_id, buffer, sector_count, SDC_FS_WRITE_PATH_USE_DMA_MSG);
	if(ret != 0)
	{
		drvl2_sd_sem_unlock(device_id);
		return ret;
	}

	ret = drvl2_sd_write_stop(device_id);
	if(ret != 0)
	{
		drvl2_sd_sem_unlock(device_id);
		return ret;
	}

	drvl2_sd_sem_unlock(device_id);
	return ret;
}

#else
INT32S drvl2_sd_write(INT32U device_id, INT32U start_sector, INT32U *buffer, INT32U sector_count)
{
	INT32U	response;
	INT32S	ret;

	drvl2_sd_sem_lock(device_id);

	drvl1_sdc_set_access_kind(device_id, C_SD_L2_ACCESS_WRITE);

	if(sd_card_state[device_id] != SD_CARD_STATE_TRANSFER)
	{
		drvl2_sd_sem_unlock(device_id);
		return -1;
	}

	drvl2_sd_set_speed_bus(device_id);
	if(drvl2_sd_card_protect_get(device_id))
	{
		drvl2_sd_sem_unlock(device_id);
		return -1;
	}

	if(drvl2_sd_card_busy_wait(device_id, C_SD_L2_CARD_BUSY_TIMEOUT))
	{
		drvl2_sd_sem_unlock(device_id);
		return -1;
	}

	if(sector_count == 1)
	{
		if((sd_card_type[device_id] == C_MEDIA_SDHC_CARD) || (sd_card_type[device_id] == C_MEDIA_MMCHC_CARD))
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD24, start_sector, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}
		else
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD24, start_sector << 9, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}

		if(drvl1_sdc_command_complete_wait(device_id, C_SD_L2_SINGLE_WRITE_CMD_COMPLETE_TIMEOUT))
		{
			drvl2_sd_sem_unlock(device_id);
			return -1;
		}

		sd_card_state[device_id] = SD_CARD_STATE_RECEIVE_DATA;

		ret = drvl1_sdc_write_data_by_dma(device_id, buffer, sector_count, NULL);

		sd_card_state[device_id] = SD_CARD_STATE_PROGRAMMING;

		if(drvl1_sdc_data_complete_wait(device_id, C_SD_L2_SINGLE_WRITE_DATA_COMPLETE_TIMEOUT))
		{
			ret = -1;
		}

		if(drvl1_sdc_data_crc_status_get(device_id))
		{
			ret = -1;
			{
				volatile sdReg_t	*sd = (sdReg_t *) SetSDBase(device_id);
				SDC_L2_PRINT("1 drvl2_sd_write crc error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
			}
		}
	}
	else
	{
		if((sd_card_type[device_id] == C_MEDIA_SDHC_CARD) || (sd_card_type[device_id] == C_MEDIA_MMCHC_CARD))
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD25, start_sector, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}
		else
		{
			if(drvl2_sd_adtc_command_set(device_id, C_SD_CMD25, start_sector << 9, 0, &response))
			{
				drvl2_sd_sem_unlock(device_id);
				return -1;
			}
		}

#if 0					// test code that produce sd timeout bit 9
		{
			volatile unsigned int	k;
			for(k = 0; k < 10000000; k++)
				;
		}

#endif
		if(drvl1_sdc_command_complete_wait(device_id, C_SD_L2_MULTI_WRITE_CMD_COMPLETE_TIMEOUT))
		{
			drvl2_sd_sem_unlock(device_id);
			return -1;
		}

		sd_card_state[device_id] = SD_CARD_STATE_RECEIVE_DATA;

		ret = drvl1_sdc_write_data_by_dma(device_id, buffer, sector_count, NULL);

		if(drvl1_sdc_data_complete_wait(device_id, C_SD_L2_MULTI_WRITE_DATA_COMPLETE_TIMEOUT))
		{
			ret = -1;
		}

		if(drvl1_sdc_data_crc_status_get(device_id))
		{
			ret = -1;
			{
				volatile sdReg_t	*sd = (sdReg_t *) SetSDBase(device_id);
				SDC_L2_PRINT("2 drvl2_sd_write crc error[%d]. status=0x%08x start=%u nr=%u\r\n", device_id, sd->Status, start_sector, sector_count);
			}
		}

		if(drvl1_sdc_stop_controller(device_id, C_SD_L2_WRITE_CONTROLLER_STOP_TIMEOUT))
		{
			ret = -1;
		}

		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD12, 0x0, C_RESP_R1B, &response))
		{
			ret = -1;
		}

		sd_card_state[device_id] = SD_CARD_STATE_PROGRAMMING;
	}

	// Wait operation complete and back to transfer state
	ret = drvl2_sd_card_busy_wait(device_id, C_SD_L2_CARD_PROGRAM_TIMEOUT);
	sd_card_state[device_id] = SD_CARD_STATE_TRANSFER;
	drvl2_sd_sem_unlock(device_id);
	return ret;
}

#endif
static INT32S drvl2_sd_card_remove_base(INT32U device_id)
{
	INT32U	response;

	if(sd_card_user[device_id] > 1)
	{
		// when ther is still other user, just minus 1 and return
		sd_card_user[device_id]--;
		return 0;
	}

	// Reset card to idle state
	if(sd_card_state[device_id] >= SD_CARD_STATE_TRANSFER)
	{
		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD13, sd_card_rca[device_id], C_RESP_R1, &response))
		{
			sd_card_state[device_id] = SD_CARD_STATE_INACTIVE;
		}
		else
		{
			if((response & 0x1E00) < 0x800)
			{
				// If card exists and not in transfer state, send it back to idle state
				drvl2_sd_bc_command_set(device_id, C_SD_CMD0, 0x0);
				drvl2_sd_bc_command_set(device_id, C_SD_CMD0, 0x0);
				drvl2_sd_bc_command_set(device_id, C_SD_CMD0, 0x0);
				sd_card_state[device_id] = SD_CARD_STATE_IDLE;
			}
			else
			if((response & 0x1E00) != 0x800)
			{
				// If card is in sending-data or receive data or programming state, send stop command
				drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD12, 0x0, C_RESP_R1B, &response);

				// Wait until card is not busy before turning off controller
				drvl2_sd_card_busy_wait(device_id, C_SD_L2_CARD_PROGRAM_TIMEOUT);
			}
		}
	}

	drvl1_sdc_disable(device_id);
	if(sd_card_user[device_id])
		sd_card_user[device_id]--;

	return 0;
}

static INT32S drvl2_sd_read_start_base(INT32U device_id, INT32U start_sector, INT32U sector_count)
{
	#if SDC_L2_DEBUG
	volatile sdReg_t *sd = (sdReg_t *) SetSDBase(device_id);
	#endif
	INT32U response;
	INT32U comamnd = (sector_count == 1) ? C_SD_CMD17 : C_SD_CMD18;

	drvl1_sdc_set_access_kind(device_id, C_SD_L2_ACCESS_READ);

	if(sd_card_state[device_id] != SD_CARD_STATE_TRANSFER)
	{
		return -1;
	}

	drvl2_sd_set_speed_bus(device_id);
	if(drvl2_sd_card_busy_wait(device_id, C_SD_L2_CARD_BUSY_TIMEOUT))
	{
		return -1;
	}

	// Clear SD RX data buffer before read command is issued
	drvl1_sdc_clear_rx_data_register(device_id);

	if((sd_card_type[device_id] == C_MEDIA_SDHC_CARD) || (sd_card_type[device_id] == C_MEDIA_MMCHC_CARD))
	{
		if(drvl2_sd_adtc_command_set(device_id, comamnd, start_sector, 0, &response))
		{
			return -1;
		}
	}
	else
	{
		if(drvl2_sd_adtc_command_set(device_id, comamnd, start_sector << 9, 0, &response))
		{
			return -1;
		}
	}

	if(drvl1_sdc_command_complete_wait(device_id, C_SD_L2_MULTI_READ_CMD_COMPLETE_TIMEOUT))
	{
		SDC_L2_PRINT("drvl2_sd_read_start_base comamnd complete wait error[%d]. status=0x%08x\r\n", device_id, sd->Status);
		return -1;
	}

	sd_card_state[device_id] = SD_CARD_STATE_SENDING_DATA;

	return 0;
}

static volatile INT8S	sd_read_sector_result[SDC_TOTAL];
static INT32S drvl2_sd_read_sector_base(INT32U device_id, INT32U *buffer, INT32U sector_count, INT8U wait_flag)
{
	INT32S	ret;

	if(wait_flag == 0)
	{
		// Start DMA and return immediately
		ret = drvl1_sdc_read_data_by_dma(device_id, buffer, sector_count, (INT8S *) &sd_read_sector_result[device_id]);
		if(ret != 0)
		{
			SDC_L2_PRINT("1 drvl2_sd_read_sector_base err %d. sector_count=%u. ret=%d\r\n", sd_read_sector_result[device_id], sector_count, ret);
		}
	}
	else
	if(wait_flag == 1)
	{
		// Start DMA and wait until done
		ret = drvl1_sdc_read_data_by_dma(device_id, buffer, sector_count, NULL);
		if(ret != 0)
		{
			SDC_L2_PRINT("2 drvl2_sd_read_sector_base err %d. sector_count=%u. ret=%d\r\n", sd_read_sector_result[device_id], sector_count, ret);
		}

		return ret;
	}

	// Query status and return when done
	while(1)
	{
		if(sd_read_sector_result[device_id] != C_DMA_STATUS_WAITING)
			break;

		//osDelay(1);
		OSTimeDly(1);
	}

	if(sd_read_sector_result[device_id] != C_DMA_STATUS_DONE)
	{
		SDC_L2_PRINT("3 drvl2_sd_read_sector_base err %d. sector_count=%u\r\n", sd_read_sector_result[device_id], sector_count);
		return -1;
	}

	return 0;
}

static INT32S drvl2_sd_read_stop_base(INT32U device_id, INT32U multiple_read)
{
	#if SDC_L2_DEBUG
	volatile sdReg_t *sd = (sdReg_t *) SetSDBase(device_id);
	#endif
	INT32U response;
	INT32S ret = 0;

	ret = 0;

	if(drvl1_sdc_data_complete_wait(device_id, C_SD_L2_MULTI_READ_DATA_COMPLETE_TIMEOUT))
	{
		ret = -1;
		SDC_L2_PRINT("drvl2_sd_read_stop_base complete wait error[%d]. status=0x%08x\r\n", device_id, sd->Status);
	}

	if(drvl1_sdc_data_crc_status_get(device_id))
	{
		ret = -1;
		SDC_L2_PRINT("drvl2_sd_read_stop_base crc error[%d]. status=0x%08x\r\n", device_id, sd->Status);
	}

	if(multiple_read)
	{
		if(drvl1_sdc_stop_controller(device_id, C_SD_L2_READ_CONTROLLER_STOP_TIMEOUT))
		{
			ret = -1;

			SDC_L2_PRINT("drvl2_sd_read_stop_base stop controller error[%d]. status=0x%08x\r\n", device_id, sd->Status);
		}

		if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD12, 0x0, C_RESP_R1B, &response))
		{
			ret = -1;	// some non brand card will happen read stop command response crc error

			// using 49.5M sd clock will always happen read data crc error
			// using 47.25M happen some data crc error, retry could pass, but alsmost always happen
			// read stop command response crc error. Must down untill 41.25M to pass.
			SDC_L2_PRINT("drvl2_sd_read_stop_base stop command error[%d]. status=0x%08x nr=%u\r\n", device_id, sd->Status, sd_flow_nr_sector[device_id]);
		}
	}

	sd_card_state[device_id] = SD_CARD_STATE_TRANSFER;

	return ret;
}

static INT32S drvl2_sd_write_start_base(INT32U device_id, INT32U start_sector, INT32U sector_count)
{
	INT32U	response;
	INT32U	command = (sector_count == 1) ? C_SD_CMD24 : C_SD_CMD25;

	drvl1_sdc_set_access_kind(device_id, C_SD_L2_ACCESS_WRITE);

	if(sd_card_state[device_id] != SD_CARD_STATE_TRANSFER)
	{
		return -1;
	}

	if(drvl2_sd_card_protect_get(device_id))
	{
		return -1;
	}

	drvl2_sd_set_speed_bus(device_id);
	if(drvl2_sd_card_busy_wait(device_id, C_SD_L2_CARD_BUSY_TIMEOUT))
	{
		return -1;
	}

	if((sd_card_type[device_id] == C_MEDIA_SDHC_CARD) || (sd_card_type[device_id] == C_MEDIA_MMCHC_CARD))
	{
		if(drvl2_sd_adtc_command_set(device_id, command, start_sector, 0, &response))
		{
			return -1;
		}
	}
	else
	{
		if(drvl2_sd_adtc_command_set(device_id, command, start_sector << 9, 0, &response))
		{
			return -1;
		}
	}

	if(drvl1_sdc_command_complete_wait(device_id, C_SD_L2_MULTI_WRITE_CMD_COMPLETE_TIMEOUT))
	{
		return -1;
	}

	sd_card_state[device_id] = SD_CARD_STATE_RECEIVE_DATA;

	return 0;
}

static volatile INT8S	sd_write_sector_result[SDC_TOTAL];
static INT32S drvl2_sd_write_sector_base(INT32U device_id, INT32U *buffer, INT32U sector_count, INT8U wait_flag)
{
	INT32S	ret;

	if(wait_flag == 0)
	{
		// Start DMA and return immediately
		ret = drvl1_sdc_write_data_by_dma(device_id, buffer, sector_count, (INT8S *) &sd_write_sector_result[device_id]);
	}
	else
	if(wait_flag == 1)
	{
		// Start DMA and wait until done
		INT32S	ret = drvl1_sdc_write_data_by_dma(device_id, buffer, sector_count, NULL);
		return ret;
	}

	// Query status and return when done
	while(1)
	{
		if(sd_write_sector_result[device_id] != C_DMA_STATUS_WAITING)
			break;

		//osDelay(1);
		OSTimeDly(1);
	}

	if(sd_write_sector_result[device_id] != C_DMA_STATUS_DONE)
	{
		return -1;
	}

	return 0;
}

static INT32S drvl2_sd_write_stop_base(INT32U device_id, INT32U multiple_write)
{
	INT32U	response;
	INT32S	ret;

	ret = 0;
	if(drvl1_sdc_data_complete_wait(device_id, C_SD_L2_MULTI_WRITE_DATA_COMPLETE_TIMEOUT))
	{
		ret = -1;
		{
			#if SDC_L2_DEBUG
			volatile sdReg_t	*sd = (sdReg_t *) SetSDBase(device_id);
			#endif
			SDC_L2_PRINT("drvl2_sd_write_stop_base. drvl1_sdc_data_complete_wait err. status=0x%08x\r\n", sd->Status);
		}
	}

	if(drvl1_sdc_data_crc_status_get(device_id))
	{
		ret = -1;
		{
			#if SDC_L2_DEBUG
			volatile sdReg_t	*sd = (sdReg_t *) SetSDBase(device_id);
			#endif
			SDC_L2_PRINT("3 drvl2_sd_write crc error[%d]. status=0x%08x\r\n", device_id, sd->Status);
		}
	}

	if(multiple_write)
	{
		if(drvl1_sdc_stop_controller(device_id, C_SD_L2_WRITE_CONTROLLER_STOP_TIMEOUT))
		{
			ret = -1;
			{
				#if SDC_L2_DEBUG
				volatile sdReg_t	*sd = (sdReg_t *) SetSDBase(device_id);
				#endif
				SDC_L2_PRINT("drvl2_sd_write_stop_base. drvl1_sdc_stop_controller err. status=0x%08x\r\n", sd->Status);
			}
		}

		drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD12, 0x0, C_RESP_R1B, &response);
		sd_card_state[device_id] = SD_CARD_STATE_PROGRAMMING;

		// Wait operation complete and back to transfer state
		ret = drvl2_sd_card_busy_wait(device_id, C_SD_L2_CARD_PROGRAM_TIMEOUT);
		if(ret != 0)
		{
			#if SDC_L2_DEBUG
			volatile sdReg_t	*sd = (sdReg_t *) SetSDBase(device_id);
			#endif
			SDC_L2_PRINT("drvl2_sd_write_stop_base. drvl2_sd_card_busy_wait err. status=0x%08x\r\n", sd->Status);
		}
	}

	sd_card_state[device_id] = SD_CARD_STATE_TRANSFER;

	return ret;
}

INT32S drvl2_sd_set_clock_ext(INT32U device_id, INT32U bus_speed)
{
	if(bus_speed > 50000000)
		return -1;		// remain unchanged
	sd_card_speed[device_id] = bus_speed;
	return 0;
}

INT32S	drvl2_sd_enforce_read_stop(INT32U device_id);

static void sd_init_flow(INT32U device_id)
{
	sd_flow_state[device_id] = SD_FLOW_IDLE;
	sd_flow_kind[device_id] = SD_FLOW_NONE;
	sd_flow_end_sector[device_id] = 0;
	sd_flow_nr_sector[device_id] = 0;
}

INT32S drvl2_sd_write_start(INT32U device_id, INT32U start_sector, INT32U sector_count)
{
	INT32S	ret;

	if(sd_flow_kind[device_id] == SD_FLOW_READ)
	{
		if(sd_flow_state[device_id] == SD_FLOW_CONTINUE)
		{
			// last read action not be ended, so ended it.
			//SDC_L2_PRINT("endforce read stop at write start. start=%u, lastend=%u, accnr=%u, ret=%d\r\n", start_sector, sd_flow_end_sector[device_id], sd_flow_nr_sector[device_id], ret);
			ret = drvl2_sd_enforce_read_stop(device_id);
			if(ret != 0)
			{
				SDC_L2_PRINT("sd_write_start:endforce read stop err %d\r\n", ret);
				return ret;
			}
		}
	}
	else
	if(sd_flow_kind[device_id] == SD_FLOW_WRITE)
	{
		if(sd_flow_state[device_id] == SD_FLOW_CONTINUE)
		{
			if((start_sector != sd_flow_end_sector[device_id]) || (sd_flow_single_sector_mode[device_id]) || (sd_flow_nr_sector[device_id] >= sd_flow_write_au_sectors[device_id]))
			{
				#if SDC_L2_DEBUG
				INT32U	save_sd_flow_end_sector = sd_flow_end_sector[device_id];
				INT32U	save_sd_flow_nr_sector = sd_flow_nr_sector[device_id];
				#endif

				// not continuos address, stop it.
				//SDC_L2_PRINT("endforce write stop at write start. start=%u, lastend=%u, accnr=%u, ret=%d\r\n", start_sector, sd_flow_end_sector[device_id], sd_flow_nr_sector[device_id], ret);
				ret = drvl2_sd_enforce_write_stop(device_id);
				if(ret != 0)
				{
					SDC_L2_PRINT("sd_write_start:endforce write stop err %d. start=%u, nr=%u, lastend=%u accnr=%u\r\n", ret, start_sector, sector_count, save_sd_flow_end_sector, save_sd_flow_nr_sector);
					return ret;
				}
			}
			else
			{
				ret = 0;
				return ret;
			}
		}
	}

	sd_flow_kind[device_id] = SD_FLOW_WRITE;
	sd_flow_state[device_id] = SD_FLOW_START;
	sd_flow_end_sector[device_id] = start_sector;
	sd_flow_nr_sector[device_id] = 0;
	sd_flow_single_sector_mode[device_id] = (sector_count == 1) ? 1 : 0;

	//SDC_L2_PRINT("write start. start=%u, nr=%u\r\n", start_sector, sector_count);
	ret = drvl2_sd_write_start_base(device_id, start_sector, sector_count);
	if(ret != 0)
	{
		SDC_L2_PRINT("sd_write_start:sd write base err %d\r\n", ret);
	}

	return ret;
}

INT32S drvl2_sd_write_sector(INT32U device_id, INT32U *buffer, INT32U sector_count, INT8U wait_flag)
{
	INT32S	ret;

	sd_flow_state[device_id] = SD_FLOW_CONTINUE;
	sd_flow_nr_sector[device_id] += sector_count;
	sd_flow_end_sector[device_id] += sector_count;

	ret = drvl2_sd_write_sector_base(device_id, buffer, sector_count, wait_flag);

	return ret;
}

INT32S drvl2_sd_enforce_write_stop(INT32U device_id)
{
	INT32S	ret;

	sd_flow_state[device_id] = SD_FLOW_STOP;
	ret = drvl2_sd_write_stop_base(device_id, (sd_flow_single_sector_mode[device_id] ? 0 : 1));
	sd_init_flow(device_id);

	return ret;
}

INT32S drvl2_sd_write_stop(INT32U device_id)
{
	INT32S	ret = 0;

	if((sd_flow_single_sector_mode[device_id]) || (sd_flow_nr_sector[device_id] >= sd_flow_write_au_sectors[device_id]))
	{
		//SDC_L2_PRINT("endforce write stop at write stop. lastend=%u, accnr=%u, ret=%d\r\n", sd_flow_end_sector[device_id], sd_flow_nr_sector[device_id], ret);
		ret = drvl2_sd_enforce_write_stop(device_id);
	}

	return ret;
}

INT32S drvl2_sd_read_start(INT32U device_id, INT32U start_sector, INT32U sector_count)
{
	INT32S	ret = 0;

	if(sd_flow_kind[device_id] == SD_FLOW_WRITE)
	{
		if(sd_flow_state[device_id] == SD_FLOW_CONTINUE)
		{
			// last write action not be ended, so ended it.
			//SDC_L2_PRINT("endforce write stop at read start. start=%u, lastend=%u, accnr=%u, ret=%d\r\n", start_sector, sd_flow_end_sector[device_id], sd_flow_nr_sector[device_id], ret);
			ret = drvl2_sd_enforce_write_stop(device_id);
			if(ret != 0)
			{
				return ret;
			}
		}
	}
	else
	if(sd_flow_kind[device_id] == SD_FLOW_READ)
	{
		if(sd_flow_state[device_id] == SD_FLOW_CONTINUE)
		{
			if((start_sector != sd_flow_end_sector[device_id]) || (sd_flow_single_sector_mode[device_id]) || (sd_flow_nr_sector[device_id] >= sd_flow_read_au_sectors[device_id]))
			{
				// not continuos address, stop it.
				//SDC_L2_PRINT("endforce read stop at read start. start=%u, lastend=%u, accnr=%u, ret=%d\r\n", start_sector, sd_flow_end_sector[device_id], sd_flow_nr_sector[device_id], ret);
				ret = drvl2_sd_enforce_read_stop(device_id);
				if(ret != 0)
				{
					return ret;
				}
			}
			else
			{
				ret = 0;
				return ret;
			}
		}
	}

	sd_flow_kind[device_id] = SD_FLOW_READ;
	sd_flow_state[device_id] = SD_FLOW_START;
	sd_flow_end_sector[device_id] = start_sector;
	sd_flow_nr_sector[device_id] = 0;

	//SDC_L2_PRINT("read start. start=%u nr=%u\r\n", start_sector, sector_count);
#if 1
	sd_flow_single_sector_mode[device_id] = (sector_count == 1) ? 1 : 0;
#else
	sd_flow_single_sector_mode[device_id] = 0;	// set to to always use multiple sector read
	sector_count = 0;	// this is to cheat drvl2_sd_read_start_base use multiple sector read
#endif
	ret = drvl2_sd_read_start_base(device_id, start_sector, sector_count);
	if(ret != 0)
	{
		SDC_L2_PRINT("sd_read_start:sd read base err %d\r\n", ret);
	}

	return ret;
}

INT32S drvl2_sd_read_sector(INT32U device_id, INT32U *buffer, INT32U sector_count, INT8U wait_flag)
{
	INT32S	ret = 0;

	sd_flow_state[device_id] = SD_FLOW_CONTINUE;
	sd_flow_nr_sector[device_id] += sector_count;
	sd_flow_end_sector[device_id] += sector_count;

	ret = drvl2_sd_read_sector_base(device_id, buffer, sector_count, wait_flag);

	return ret;
}

INT32S drvl2_sd_enforce_read_stop(INT32U device_id)
{
	INT32S	ret = 0;

	sd_flow_state[device_id] = SD_FLOW_STOP;
	ret = drvl2_sd_read_stop_base(device_id, (sd_flow_single_sector_mode[device_id] ? 0 : 1));
	sd_init_flow(device_id);

	return ret;
}

INT32S drvl2_sd_read_stop(INT32U device_id)
{
	INT32S	ret = 0;

	if((sd_flow_single_sector_mode[device_id]) || sd_flow_nr_sector[device_id] >= sd_flow_read_au_sectors[device_id])
	{
		//SDC_L2_PRINT("endforce read stop at read stop. lastend=%u, accnr=%u, ret=%d\r\n", sd_flow_end_sector[device_id], sd_flow_nr_sector[device_id], ret);
		ret = drvl2_sd_enforce_read_stop(device_id);
	}

	return ret;
}

static INT32S drvl2_sd_flush_base(INT32U device_id)
{
	INT32S	ret = 0;

	if(sd_flow_kind[device_id] == SD_FLOW_READ)
	{
		if((sd_flow_state[device_id] == SD_FLOW_CONTINUE) || (sd_flow_state[device_id] == SD_FLOW_START))
		{
			// last read action not be ended, so ended it.
			ret = drvl2_sd_enforce_read_stop(device_id);

			//SDC_L2_PRINT("drvl2_sd_flush enfore read stop\r\n");
			if(ret != 0)
			{
				//return ret;
			}
		}
	}
	else
	if(sd_flow_kind[device_id] == SD_FLOW_WRITE)
	{
		if((sd_flow_state[device_id] == SD_FLOW_CONTINUE) || (sd_flow_state[device_id] == SD_FLOW_START))
		{
			// last write action not be ended, so ended it.
			ret = drvl2_sd_enforce_write_stop(device_id);

			//SDC_L2_PRINT("drvl2_sd_flush enfore write stop\r\n");
			if(ret != 0)
			{
				//return ret;
			}
		}
	}

	return ret;
}

INT32S drvl2_sd_flush(INT32U device_id)
{
	INT32S	ret;

	drvl2_sd_sem_lock(device_id);
	ret = drvl2_sd_flush_base(device_id);
	drvl2_sd_sem_unlock(device_id);

	return ret;
}

INT32S drvl2_sd_card_remove(INT32U device_id)
{
	INT32S	ret;

	drvl2_sd_sem_lock(device_id);
	drvl2_sd_flush_base(device_id);
	ret = drvl2_sd_card_remove_base(device_id);
	drvl2_sd_sem_unlock(device_id);

	return ret;
}

#if C_GPIO_SPEEDUP_SD_CHECK == CUSTOM_ON
INT32S sdc_detect_pin_status_get(void)
{
	INT32U	retStatus;

	retStatus = gpio_read_io(SDC_DETECT_PIN);
	if(retStatus == SDC_DETECT_PIN_ACTIVE)
	{
		return 0;		// Plug In
	}
	else
	{
		return 1;		// Plug Out
	}
}

#endif
INT32S drvl2_sdc_live_response(INT32U device_id)
{
	INT32U	response;

#if C_GPIO_SPEEDUP_SD_CHECK == CUSTOM_ON
	if(sdc_detect_pin_status_get() == 0)
	{
		// Card exist
		return 0;
	}
	else
	{
		// Card not exist
		return -1;
	}

#else
	drvl2_sd_sem_lock(device_id);
	drvl2_sd_flush_base(device_id);
	if(drvl2_sd_bcr_ac_command_set(device_id, C_SD_CMD13, sd_card_rca[device_id], C_RESP_R1, &response) == 0)
	{
		// Card exist
		drvl2_sd_sem_unlock(device_id);
		return 0;
	}
	else
	{
		// Card not exist
		drvl2_sd_sem_unlock(device_id);
		return -1;
	}

#endif
}

#endif // _DRV_L2_SDC
